/*
 * @Author: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
 * @Date: 2025-02-10 14:51:17
 * @LastEditors: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
 * @LastEditTime: 2025-02-11 15:28:52
 * @FilePath: /2024-4-20-pipe/shm/shm.hpp
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#ifndef __SHM_HPP__
#define __SHM_HPP__

#include <iostream>
#include <string>
#include <cerrno>
#include <cstdio>
#include <cstring>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <unistd.h>

using namespace std;

const int gCreator = 1;
const int gUser = 2;

const string gpathname = "/home/yjl/lesson/2024-4-20-pipe/shm";
const int gproj_id = 0x66;
const int gShmSize = 4096;

class Shm
{
private:
    // 获取key的函数
    key_t GetCommonKey()
    {
        key_t k = ftok(_pathname.c_str(), _proj_id);
        if (k < 0)
        {
            perror("ftok");
        }
        return k;
    }
    // 获取shmid（shmid==shmget函数的返回值）的函数
    int GetShmHelper(key_t key, int size, int flag)
    {
        int shmid = shmget(key, size, flag);
        if (shmid < 0)
        {
            perror("shmget");
        }
        return shmid;
    }

    string RoleToString(int who)
    {
        if (who == gCreator)
            return "Creator";
        else if (who == gUser)
            return "User";

        return "None";
    }

    // 挂接：
    void *AttachShm()
    {
        if (_addrshm != nullptr)
            DelShm(_addrshm);
        void *shmaddr = shmat(_shmid, nullptr, 0);

        if (shmaddr == nullptr)
        {
            perror("shmat");
        }
        cout << "who->" << RoleToString(_who) << "attach the shm..." << endl;
        return shmaddr;
    }

    // 删除共享内存:shmdt
    void DelShm(void *shmaddr)
    {
        if (shmaddr == nullptr)
            return;
        shmdt(shmaddr);
        cout << "who->" << RoleToString(_who) << "delect the shm..." << endl;
    }

public:
    Shm(const string &pathname, int proj_id, int who)
        : _pathname(pathname), _proj_id(proj_id), _who(who), _addrshm(nullptr)
    {
        _key = GetCommonKey();
        if (who == gCreator)
            GetShmUseCreate();
        else if (who == gUser)
            GetShmUser();

        _addrshm = AttachShm(); // 把挂接函数也直接封装到：构造函数里面(极度封装：只要用Shm这个类成功创建出来变量，就直接挂接了！)

        cout << "shmid->" << _shmid << endl;
        cout << "_key->" << ToHex(_key) << endl;
    }
    ~Shm()
    {
        if (_who == gCreator)
        {
            int ret = shmctl(_shmid, IPC_RMID, nullptr);
        }
        cout << "shm remove done..." << endl;
    }
    // 将key转化为16进制的函数
    string ToHex(key_t key)
    {
        char buffer[128];
        snprintf(buffer, sizeof(buffer), "0x%x", key);
        return buffer;
    }

    bool GetShmUseCreate()
    {
        if (_who == gCreator)
        {
            _shmid = GetShmHelper(_key, gShmSize, IPC_CREAT | IPC_EXCL| 0666);
            sleep(2);
            if (_shmid >= 0)
                return true;
            cout << "shm create done..." << endl;
        }
        return false;
    }
    bool GetShmUser()
    {
        if (_who == gUser)
        {
            _shmid = GetShmHelper(_key, gShmSize, IPC_CREAT | 0666);
            if (_shmid >= 0)
                return true;
            cout << "shm get done..." << endl;
        }
        return false;
    }

    void Zero() // 先对共享内存清空！
    {
        if (_addrshm)
        {
            memset(_addrshm, 0, gShmSize);
        }
    }

    void *Addr()
    {
        return _addrshm;
    }

private:
    key_t _key;
    int _shmid;

    string _pathname;
    int _proj_id;

    int _who;

    void *_addrshm;
};

#endif